// useCallback
// useCallback 用于优化性能，返回一个记忆化的回调函数，可以减少不必要的重新渲染，也就是说它是用于缓存组件内的【函数】，避免函数的重复创建。
// 1.什么场景造成的性能问题？为什么有性能问题？为什么需要useCallback？
// 在React中，函数组件的重新渲染会导致组件内的函数(删除)被重新创建，这可能会导致性能问题。
// useCallback 通过缓存函数，可以减少不必要的重新渲染【或者函数里面调用接口，就减少了调用接口】，提高性能。

// 2.语法
// const cachedFn = useCallback(fn, dependencies)
// fn: 需要缓存的函数。
// dependencies: 缓存函数的依赖项，当依赖项发生变化时，缓存的函数会被重新创建。
// 返回值
// cachedFn: 缓存的函数。
// const memoizedCallback = useCallback(() => {
//   doSomething(a, b);
// }, [a, b]);

// 3.使用场景
// 3-1.重新渲染组件时，不需要执行的方法，把它缓存起来。
// 3-2.在函数组件中，需要传递给子组件的函数，使用useCallback在父组件中缓存父组件传递的函数，避免了子组件重新渲染，减少不必要的性能消耗。
//    Q：3-2，不是使用了React.memo包裹后，只有改变props,子组件才会重新渲染？为什么传多了个函数，就一直子组件重新渲染？
//    A: 观察笔记中的截图，为什么会有这个问题

// 4.案例
// 4-1.验证函数删除又重新创建
// 4-2.验证3-2  需要传递给子组件的函数，使用useCallback优化之后，子组件不会重新渲染了。

// 5.与useMemo的区别
// useCallback用于缓存函数，而useMemo用于缓存值。

// 6.总结
// 谨慎使用，因为函数是缓存在内存中的，会有内存消耗！
// useCallback的使用需要有所节制，不要盲目地对每个方法应用useCallback，这样做可能会导致不必要的性能损失。useCallback本身也需要一定的性能开销。
// useCallback并不是为了阻止函数的重新创建，而是通过依赖项来决定是否返回新的函数或旧的函数，从而在依赖项不变的情况下确保函数的地址不变。

import { Button, Flex, Input } from 'antd';
import React, { useCallback, useState } from 'react';
const functionMap = new WeakMap();
let counter = 1;

interface User {
  name: string;
  age: number;
}

interface ChildProps {
  user: User
  update: () => void
}

// 验证3-2
const Child = React.memo(({user, update}: ChildProps) => {
  console.log('子组件重新渲染了');  // 发现没有修改user的值，子组件也被重新渲染了 ; 对比使用useCallback包住传进来的函数update
  
  return (
    <>
      <h3>子组件：用户信息</h3>
      <div>姓名{user.name}</div>
      <div>年龄{user.age}</div>
      <Button onClick={update}>调用传进来的方法修改User</Button>
    </>
  );
});
const App: React.FC = () => {
  const [keyword, setKeyword] = useState('');
  const [user, setUser] = useState({
    name: '张三',
    age: 18
  });
  // const changeSearch = (e: React.ChangeEvent<HTMLInputElement>) => {
  //   setKeyword(e.target.value);
  // };

  // 3-1.重新渲染组件时，把它缓存起来，函数就不会创建多次。
  const changeSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    setKeyword(e.target.value);
  }, []);

  // 4-1.验证函数删除又重新创建
  if (!functionMap.has(changeSearch)) {
    functionMap.set(changeSearch, counter++);
  }
  console.log('函数Id', functionMap.get(changeSearch));
  // 验证4-1 我们更改输入框的值，可以看到函数Id在增加，说明函数被重新创建了。 //输出函数Id counter++
  // 验证3-1 useCallback优化之后，changeSearch函数被缓存了，不会重新创建。  //输出函数Id 1


  // 验证 4-2
  // const update = () => {
  //   console.log('修改');
  // }
  // 使用useCallback包住
  const [count, setCount] = useState(0);
  const update = useCallback(() => {
    console.log('修改');
  }, [count])


  return (
    <>
      <Flex>
        <Input placeholder="请输入关键字" value={keyword} onChange={changeSearch} />
        <Button onClick={() => setCount(count + 1)}>+</Button>
      </Flex>
      <Child user={user} update={update} />
    </>
  );
};

export default App;
